package com.apes.enquiry.product.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.enquiry.brand.model.SpBrand;
import com.apes.enquiry.brand.repository.SpBrandRepository;
import com.apes.enquiry.product.model.SpProduct;
import com.apes.enquiry.product.model.TyreProduct;
import com.apes.enquiry.product.repository.*;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.MapUtil;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import com.apestech.framework.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @className: com.apes.enquiry.product.service.TyreProductService
 * @description: 描述:轮胎类商品服务类
 * @author: wsl
 * @create: 2022-11-08 17:10
 */
@Service
public class TyreProductService extends DomainService {
    @Autowired
    private SpBrandRepository spBrandRepository;

    @Autowired
    private TyreProductRepository tyreProductRepository;

    @Autowired
    private SpProductRepository spProductRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 上轮胎池商品入口
     *
     * @param request
     */
    public void uploadingTyreProduct(SimpleRequest request) {
        //Excel信息
        JSONObject importData = request.get("importData");
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        //准入校验与数据补全
        List tyreProducts = appendImportReturn_New(importData, user);
        if (tyreProducts.size() <= 0) return;
        List tyreProduct = Collections.synchronizedList(new ArrayList());
        for(int i=0;i<tyreProducts.size();i++){
            tyreProduct.add(tyreProducts.get(i));
            if((i!=0 && i%1000==0) || i==tyreProducts.size()-1){
                SimpleDateFormat sdf = new SimpleDateFormat("yy-mm-dd HH:mm:ss");
                //通过事务发件箱实现标准对照/状态字段回写
                OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
                wrapper.setSubscriber("sp.tyreProduct.standardContrast");
                String random = String.valueOf(Math.random()).substring(0,3);
                //聚合根ID（非必项）tp:方便追溯发生异常的服务,(当前用户账号加时间戳)
                wrapper.setAggregateId(user.getOrigin() + sdf.format(new Date())+random);
                wrapper.setPayload(JSON.toJSONString(tyreProduct));
                SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
                tyreProduct=Collections.synchronizedList(new ArrayList());
            }
        }
    }

    /**
     * 准入校验与数据补全
     *
     * @param importData
     * @param user
     * @return
     */
    private List appendImportReturn_New(JSONObject importData, User user) {
        List tyreProducts = Collections.synchronizedList(new ArrayList());
        List notProducts = Collections.synchronizedList(new ArrayList());
        //零件号+品牌列表
        Set<String> PNAndBrand = spProductRepository.findPNAndBrandAll();
        //品牌列表
        List<String> allName = spBrandRepository.findAllName();
        //开始校验数据
        importData.forEach((k, v) -> {
            JSONArray importArray = (JSONArray) v;
            if(((JSONArray) importArray.get(0)).size()!=15) throw new RuntimeException("导入模板错误，请检查文件并重新上传！");
            if (importArray.size() > 10000) throw new RuntimeException("系统单次导入最大可以接受1W条数据，请检查文件大小并重新上传！");
            AtomicInteger i = new AtomicInteger(1);
            double size = importArray.size();
            importArray.parallelStream().forEach(item -> {
                JSONArray iValueArray = (JSONArray) item;
                //进度条
                i.getAndIncrement();
                double percent = (i.get() / size) * 100;
                int progress = (int) percent;
                stringRedisTemplate.opsForValue().set("Tyre" + user.getOrigin(), "" + progress, 2, TimeUnit.MINUTES);
                //跳过列名和导入规则行
                if (iValueArray.size() < 3 || "零件号".equals(iValueArray.getString(0))) return;
                String GuaranteePeriod = "";
                for (int n = 0; n < iValueArray.size(); n++) {
                    if (Objects.isNull(iValueArray.get(n))) continue;
                    switch (n) {
                        case 11: GuaranteePeriod = iValueArray.getString(11);
                            break;
                    }
                }
                //0、零件号 1、品牌 2、商品名称 3、商家编码 4、规格 5、花纹 6、载重指数 7、速度等级 8、是否防爆 9、产品描述 10、库存数量 11、不含税单价 12、上架状态
                String[] strings = {iValueArray.getString(1), iValueArray.getString(8)};
                if (iValueArray.size() > 8 && UploadingProductUtil.isAllNotEmpty(iValueArray.getString(0), iValueArray.getString(1),
                        iValueArray.getString(4), iValueArray.getString(5), iValueArray.getString(6), iValueArray.getString(7),
                        iValueArray.getString(8))&&("".equals(GuaranteePeriod)||"0".equals(GuaranteePeriod)||"1".equals(GuaranteePeriod)||
                        "3".equals(GuaranteePeriod)||"6".equals(GuaranteePeriod)||"12".equals(GuaranteePeriod)||"24".equals(GuaranteePeriod)) && this.formatCheck(strings, allName)
                        && PNAndBrand.add(iValueArray.getString(0) + iValueArray.getString(1) + user.getPerson().getId())) {
                    //数据初始化与数据补全
                    SpProduct spProduct = new SpProduct();
                    spProduct.setName(iValueArray.getString(2));
                    spProduct.setSupplier(user.getPerson());
                    spProduct.setType("轮胎");
                    spProduct.setSpBrand(spBrandRepository.findByName(iValueArray.getString(1)));
                    spProduct.setQuality(spProduct.getSpBrand().getQualityName());
                    spProduct.setOE(iValueArray.getString(0));
                    if(GuaranteePeriod.equals("")){
                        spProduct.setGuaranteePeriod("0");
                    }else{
                        spProduct.setGuaranteePeriod(GuaranteePeriod);
                    }
                    spProduct.setMerchantProduct(iValueArray.getString(3));
                    //非必填数据
                    maybe(iValueArray, spProduct);
                    //主数据数据补全
                    spProduct.setMateState("underway");
                    spProduct.setProductState("review");
                    spProduct.setStandardType("Tyre");

                    //轮胎数据补全
                    TyreProduct tyreProduct = new TyreProduct();
                    tyreProduct.setSpProduct(spProductRepository.saveAndFlush(spProduct));
                    tyreProduct.setSpecification(iValueArray.getString(4));
                    tyreProduct.setFigure(iValueArray.getString(5));
                    tyreProduct.setLoadIndex(iValueArray.getString(6));
                    tyreProduct.setSpeedClass(iValueArray.getString(7));
                    tyreProduct.setAntiExplosion("是".equals(iValueArray.getString(8)));
                    //保存
                    tyreProducts.add(tyreProductRepository.save(tyreProduct));
                } else {
                    notProducts.add(UploadingProductUtil.tyreCause(iValueArray, allName, PNAndBrand, user.getPerson().getId()));
                }

            });
        });
        tyreProductRepository.flush();
        //用Redis，缓存进度条和结果
        stringRedisTemplate.opsForValue().set("not_tyreProducts" + user.getOrigin(), notProducts.toString(), 2, TimeUnit.HOURS);
        //进度条
        stringRedisTemplate.opsForValue().set("Tyre" + user.getOrigin(), "100", 2, TimeUnit.MINUTES);
        //用于结果页面展示
        stringRedisTemplate.opsForValue().set("successfulTyre" + user.getOrigin(), "" + tyreProducts.size(), 4, TimeUnit.MINUTES);
        stringRedisTemplate.opsForValue().set("failingTyre" + user.getOrigin(), "" + notProducts.size(), 4, TimeUnit.MINUTES);
        return tyreProducts;
    }

    /**
     * 非必填数据，防止下标越界
     *
     * @param iValueArray
     * @param spProduct
     */
    private void maybe(JSONArray iValueArray, SpProduct spProduct) {
        spProduct.setNotTaxUnitPrice(0.00);
        spProduct.setMerchantStockQty(0);
        spProduct.setPutawayState(false);
        switch (iValueArray.size()){
            case 10:{
                spProduct.setDescribe(iValueArray.getString(9));
                break;
            }
            case 11:{
                spProduct.setDescribe(iValueArray.getString(9));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(10)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(10)) ? iValueArray.getInteger(10) : 0);
                break;
            }
            case 12:{
                spProduct.setDescribe(iValueArray.getString(9));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(10)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(10)) ? iValueArray.getInteger(10) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(11)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(11)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(11))) : 0L);
                break;
            }
            case 13:{
                spProduct.setDescribe(iValueArray.getString(9));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(10)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(10)) ? iValueArray.getInteger(10) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(11)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(11)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(11))) : 0L);
                spProduct.setPutawayState("上架".equals(iValueArray.getString(12)));
                break;
            }
            case 14:{
                spProduct.setDescribe(iValueArray.getString(9));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(10)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(10)) ? iValueArray.getInteger(10) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(11)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(11)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(11))) : 0L);
                spProduct.setPutawayState("上架".equals(iValueArray.getString(12)));
                spProduct.setDescribe(iValueArray.getString(13));
                break;
            }
            case 15:{
                spProduct.setDescribe(iValueArray.getString(9));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(10)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(10)) ? iValueArray.getInteger(10) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(11)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(11)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(11))) : 0L);
                spProduct.setPutawayState("上架".equals(iValueArray.getString(12)));
                spProduct.setDescribe(iValueArray.getString(13));
                break;
            }
        }
    }


    /**
     * 标准对照与字段回写
     *
     * @param outboxPayloadWrapper
     */
    @OutboxSubscriber(id = "sp.tyreProduct.standardContrast", name = "通过事务发件箱实现标准对照/状态字段回写")
    public void standardContrast(OutboxPayloadWrapper outboxPayloadWrapper) {
        //导入商品数据
        JSONArray importData = JSON.parseArray(outboxPayloadWrapper.getPayload());

        //数据中心标准数据
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("key", "value");
        JSONObject json = JSON.parseObject(super.invoke("dc.tyreProduct.findAllByStandard", jsonObject));
        JSONArray body = json.getJSONArray("body");
        Set<String> set = new HashSet<>();
        //数据对比与状态回写，将品牌+规格+花纹+载重指数+速度等级+是否防爆做为map的key
        Map<String, JSONObject> conditionMap = body.parallelStream().filter(data -> {
            JSONObject tyre = (JSONObject)data;
            String upperCase = (tyre.getString("brand") + tyre.getString("specification") + tyre.getString("figure") +
                    tyre.getString("loadIndex") + tyre.getString("speedClass") + tyre.getString("antiExplosion")).toUpperCase();
            return Objects.nonNull(data) && set.add(upperCase);
        }).collect(Collectors.toMap(item -> {
                    JSONObject tyreProduct = (JSONObject) item;
                    return (tyreProduct.getString("brand") + tyreProduct.getString("specification") + tyreProduct.getString("figure") +
                            tyreProduct.getString("loadIndex") + tyreProduct.getString("speedClass") + tyreProduct.getString("antiExplosion")).toUpperCase();
                },
                item -> {
                    JSONObject tyreProduct = (JSONObject) item;
                    return tyreProduct;
                }));

        //匹配
        importData.stream().forEach(item -> {
            String id = ((JSONObject) item).getString("id");
            TyreProduct tyreProduct = null;
            if(StringUtil.isEmpty(((JSONObject) item).getString("oE"))){
                tyreProduct = tyreProductRepository.findOne(id);
            }else {
                tyreProduct =  tyreProductRepository.findBySpId(id);
            }

            if(tyreProduct!=null){
                JSONObject normalData = conditionMap.get((tyreProduct.getSpProduct().getSpBrand().getName() + tyreProduct.getSpecification() + tyreProduct.getFigure() +
                        tyreProduct.getLoadIndex() + tyreProduct.getSpeedClass() + tyreProduct.isAntiExplosion()).toUpperCase());

                //状态回写
                if (Objects.nonNull(normalData)) {
                    //匹配成功
                    SpProduct spProduct = tyreProduct.getSpProduct();
                    spProduct.setMateState("succeed");
                    spProduct.setProductState(spProduct.isPutawayState() ? "offer" : "awaitPutaway");
                    spProduct.setStandardId(normalData.getString("id"));
                    spProductRepository.saveAndFlush(spProduct);
                } else {
                    //匹配失败
                    SpProduct spProduct = tyreProduct.getSpProduct();
                    spProduct.setMateState("fail");
                    spProduct.setProductState("notOffer");
                    spProductRepository.saveAndFlush(spProduct);
                }
            }
        });
    }

    /**
     * String格式校验
     *
     * @param strings
     * @return
     */
    public boolean formatCheck(String[] strings, List<String> allName) {
        if (strings.length == 0) {
            return false;
        }

        for (String item : strings) {
            if (allName.contains(item) || "是，否".contains(item)) {
                continue;
            }
            return false;
        }
        return true;
    }

    /**
     * 进度条
     *
     * @return
     */
    public String progress(SimpleRequest request) {
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        String tyre = stringRedisTemplate.opsForValue().get("Tyre" + user.getOrigin());
        if ("100".equals(tyre)) stringRedisTemplate.delete("Tyre" + user.getOrigin());
        return tyre;
    }

    /**
     * 上传结果
     *
     * @param request
     * @return
     */
    public String resultPage(SimpleRequest request) {
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        return "本次成功导入" + stringRedisTemplate.opsForValue().get("successfulTyre" + user.getOrigin()) + "条\n" +
                "导入失败" + stringRedisTemplate.opsForValue().get("failingTyre" + user.getOrigin()) + "条";
    }

    /**
     * 下载失败结果
     *
     * @param request
     * @return
     */
    public Map detail(SimpleRequest request) {
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        String tyreProducts = stringRedisTemplate.opsForValue().get("not_tyreProducts" + user.getOrigin());
        JSONArray objects = JSONArray.parseArray(tyreProducts);
        assert objects != null;
        stringRedisTemplate.delete("not_tyreProducts" + user.getOrigin());
        return MapUtil.mapper("content", new ArrayList<>(objects), "total", objects.size(), "pages", request.get("page"));
    }

    /**
     * 添加轮胎报价弹窗
     * @param request
     * @return
     */
    public Map findByBrandAndFigure(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        JSONArray condition = requestJO.getJSONArray("condition");
        JSONObject param = new JSONObject();
        param.put("specification", requestJO.getJSONObject("conditionModel").getString("oe"));
        condition.forEach(o -> {
            JSONObject item = (JSONObject) o;
            if ("brand".equals(item.getString("field"))){
                SpBrand spBrand = spBrandRepository.findOne(item.getString("value"));
                param.put("brand", spBrand.getName());
            }
            if ("figure".equals(item.getString("field"))){
                param.put("figure", item.getString("value"));
            }
            if ("antiExplosion".equals(item.getString("field"))){
                param.put("antiExplosion", item.getBoolean("value"));
            }

        });
        param.put("page", requestJO.getIntValue("page"));
        JSONObject result = invoke("dc.tyreProduct.conditionQuery", param);
        result.getJSONArray("content").toJavaList(JSONObject.class).forEach(item->{
            SpBrand brand = spBrandRepository.findByName(item.getString("brand"));
            item.put("ZBQ", getMonth(brand.getQualityId()));
        });
        return result;
    }

    public List findFigure(SimpleRequest request){
        String key = request.get("key");
        return tyreProductRepository.findByFigure(key);
    }

    //根据品质获取质保期
    private int getMonth(String qualityId) {
        int month = 12;
        if ("001".equals(qualityId)){
            month = 3;
        }
        if ("004".equals(qualityId)){
            month = 1;
        }
        return month;
    }
}
